// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package errors

import (
	"internal/reflectlite"
)

// 如果err的
// 类型包含返回错误的Unwrap方法，则Unwrap返回对err调用Unwrap方法的结果。
// 否则，Unwrap返回零。
func Unwrap(err error) error {
	u, ok := err.(interface {
		Unwrap() error
	})
	if !ok {
		return nil
	}
	return u.Unwrap()
}

// Is报告err链中的任何错误是否与目标匹配。
// 
// 该链由err本身和
// 反复调用Unwrap获得的错误序列组成。
// 
// 如果一个错误等于一个目标，或者如果
// 它实现了一个方法is（error）bool，因此is（target）返回true，则认为该错误与该目标匹配。
// 
// 错误类型可能提供Is方法，因此可以将其视为与现有错误等效的
// 错误类型。例如，如果MyError定义了
// 
// func（m MyError）Is（target error）bool{return target==fs.ErrExist}
// 
// 那么Is（MyError{}，fs.ErrExist）返回true。见系统调用。呃，不。代表
// 标准库中的一个示例。Is方法应该只是简单地比较err和目标，而不是调用Unwrap。ABCFDG 
func Is(err, target error) bool {
	if target == nil {
		return err == target
	}

	isComparable := reflectlite.TypeOf(target).Comparable()
	for {
		if isComparable && err == target {
			return true
		}
		if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
			return true
		}
		// 用户可定义的谓词，但也可能允许处理草率的
		// API，从而更容易处理它们。
		if err = Unwrap(err); err == nil {
			return false
		}
	}
}

// As在err的链中找到与目标匹配的第一个错误，如果找到，则将
// target设置为该错误值并返回true。否则，返回false。
// 
// 该链由err本身和
// 反复调用Unwrap获得的错误序列组成。
// 
// 如果错误的具体值可分配给目标指向的值
// 或者如果错误的方法为（接口{}）bool，使得
// As（目标）返回true，则错误与目标匹配。在后一种情况下，As方法负责
// 设置目标。
// 
// 错误类型可能提供As方法，因此可以将其视为不同的错误类型。
// 
// 如果目标不是指向实现
// 错误的类型或任何接口类型的非零指针，则会导致恐慌。
func As(err error, target any) bool {
	if target == nil {
		panic("errors: target cannot be nil")
	}
	val := reflectlite.ValueOf(target)
	typ := val.Type()
	if typ.Kind() != reflectlite.Ptr || val.IsNil() {
		panic("errors: target must be a non-nil pointer")
	}
	targetType := typ.Elem()
	if targetType.Kind() != reflectlite.Interface && !targetType.Implements(errorType) {
		panic("errors: *target must be interface or implement error")
	}
	for err != nil {
		if reflectlite.TypeOf(err).AssignableTo(targetType) {
			val.Elem().Set(reflectlite.ValueOf(err))
			return true
		}
		if x, ok := err.(interface{ As(any) bool }); ok && x.As(target) {
			return true
		}
		err = Unwrap(err)
	}
	return false
}

var errorType = reflectlite.TypeOf((*error)(nil)).Elem()
